- 1402/02/29
- 0
- 77
میکروسرویس
سلام سناریویی که مد نظر من هست اینه که یه برنامه ویو جی اس دارم و میخوام با identity server لاگین کنم و یک توکن بگیرم که حاوی اطلاعات یوزر و کلاینت هست.و با استفاده از این توکن به سرویس های مختلف درخواست ارسال کنم و خدمات بگیرم.(با توجه به اینکه اون سرویس ها با identity server )من پروتکت شده اند.برای این سناریو سمت identity سرور چه نوع grant type باید برای این نوع کلاینت در نظر بگیرم؟
و ایا این grant type که لحاظ کردم قابلیت این را دارد که بتوانم رفرش توکن نیز دریافت کنم ؟
سوال بعدی من اینه که من سرویس های مختلف دارم و داخل هر کدام سترسی کاربر را چک می کنم از لحاظ نقش و پرمیژن و ...
ایا این موارد که داخل جدولی ذخیره میشوند این جداول درون دیتابیس identity server من قرار میگیرند یا اینکه به ازای هر سرویس ای پی ای که دیتابیس جدا به ازای هر کدام دارم درون اینها جدا قرار دارند.
با توجه به اینکه ولید بودن توکن بوسیله ایدنتتی انجام میشه این دسترسی هم باید توسط ایدنتتی انجام بشه؟
پیشاپیش ممنونم که جواب بنده رو میدید
- 1402/02/30
برای این نوع برنامهها، نوع درخواستی که معمولاً استفاده میشود "Authorization Code with PKCE" است. این مدل امنترین روش برای این نوع برنامهها است و به شما امکان رفرش توکن را نیز میدهد.
در مورد قسمت دوم سوال شما، جواب بستگی به ساختار کلی سیستم شما دارد. معمولاً، برای مدیریت نقشها و دسترسیها، اطلاعات در دیتابیس Identity Server ذخیره میشود. ولی اگر هر سرویس از دیتابیس مجزا استفاده میکند و برای هر سرویس نقشها و دسترسیها متفاوت هستند، ممکن است لازم باشد اطلاعات در هر دیتابیس جداگانه ذخیره شود.
این نکته مهم است که تصدیق (Authentication) و اجازهدهی (Authorization) دو عملیات مجزا هستند. Identity Server فقط تصدیق را انجام میدهد، یعنی تایید میکند که کاربر کیست. بخش اجازهدهی، که شامل تشخیص نقشها و دسترسیها است، معمولاً در سمت سرویس یا برنامه انجام میشود. با این حال، اطلاعات مربوط به نقشها و دسترسیها میتواند در توکن ذخیره شود، بنابراین سرویسها میتوانند بر اساس این اطلاعات تصمیم بگیرند. در نهایت، سیستم شما باید بتواند توکنها را بررسی کند و تصمیم بگیرد که کاربر اجازه استفاده از سرویس را دارد یا خیر.
"Authorization Code with PKCE" یکی از الگوهای امنیتی است که معمولاً برای کلاینتهایی که نمیتوانند رمز Client Secret را بیخطر نگه دارند استفاده میشود. این الگو بیشتر برای برنامههای وب SPA و برنامههای موبایل استفاده میشود. PKCE به معنی "Proof Key for Code Exchange" است و یک روش امنیتی اضافی برای جلوگیری از حملات "authorization code interception attack" است.
در حالت ساده، جریان کار به این صورت است:
- کلاینت یک کد تصادفی را به عنوان "code_verifier" تولید میکند.
- کلاینت یک نسخه hash شده از "code_verifier" را به عنوان "code_challenge" ایجاد میکند.
- کلاینت درخواست اجازه دسترسی (Authorization Request) را به سرور ارسال میکند و "code_challenge" و "code_challenge_method" را به آن اضافه میکند.
- کاربر اعتبارسنجی میشود و یک "authorization code" به کلاینت برگشت داده میشود.
- کلاینت "authorization code" و "code_verifier" را به سرور درخواست توکن ارسال میکند.
- سرور "code_challenge" را با استفاده از "code_verifier" که دریافت کرده است تأیید میکند. اگر مطابقت داشته باشد، یک توکن برای کلاینت صادر میکند.
اکنون در مورد انواع مختلف grant types در OAuth2 صحبت کنیم:
-
Authorization Code: این الگو برای برنامههای وب که امکان امن نگهداری Client Secret را دارند، استفاده میشود. به این ترتیب، کاربر به صورت مستقیم اعتبارسنجی میشود و یک authorization code دریافت میکند که میتواند تبدیل به یک توکن شود.
-
Implicit: این الگو برای برنامههای Single-Page Application (SPA) که نمیتوانند رمز Client Secret را بیخطر نگه دارند استفاده میشود. در این حالت، کاربر به صورت مستقیم یک توکن دریافت میکند. البته این الگو به دلیل مشکلات امنیتی کمتر توصیه میشود و به جای آن از "Authorization Code with PKCE" استفاده میکنند.
-
Resource Owner Password Credentials: این الگو برای مواقعی است که کاربر به برنامه اعتماد کامل دارد و رمز عبور خود را به آن میدهد. در این حالت، برنامه مستقیماً رمز عبور را به سرور ارسال میکند و یک توکن دریافت میکند. این الگو فقط در شرایط خاصی توصیه میشود و عموماً در سناریوهای دیگر بهتر است از آن استفاده نشود.
-
Client Credentials: در این الگو، فقط برنامه با سرور ارتباط برقرار میکند و هیچ کاربر واقعی درگیر نیست. برنامهها با استفاده از Client ID و Client Secret خود مستقیماً از سرور یک توکن دریافت میکنند.
-
Device Code: این الگو برای دستگاههایی است که ورودی محدود یا عدم دسترسی به مرورگر دارند. کاربر با استفاده از یک دستگاه دیگر (مانند تلفن همراه یا کامپیوتر) میتواند وارد شود و تایید کند که دستگاه اجازه دستریابی به اکانت کاربری او را دارد.
به عنوان یادآوری، همیشه باید براساس محیط خود، نوع کلاینت و ریسک امنیتی، نوع مناسب درخواست را انتخاب کنید.
- 1402/02/30
مثالی که ارائه میدهم برای فرآیند احراز هویت با استفاده از پروتکل OAuth2 و جریان PKCE است. برای سادگی، این مثال فرض میکند که همه چیز به صورت همزمان اجرا میشود و از کتابخانههای کمکی استفاده میکند.
مرحله اول: ساخت درخواست اجازه (Authorization Request)
برای این مرحله، کلاینت باید یک "code_verifier" تولید کند و سپس "code_challenge" را از آن بسازد. کلاینت سپس باید درخواستی را به سرور ارسال کند که شامل "client_id", "redirect_uri", "code_challenge", و "code_challenge_method" میشود.
import axios from "axios";
import crypto from "crypto";
import querystring from "querystring";
// 1. تولید کد تصادفی به عنوان "code_verifier"
let code_verifier = crypto.randomBytes(64).toString('hex');
// 2. تولید "code_challenge" با هش کردن "code_verifier"
let hash = crypto.createHash('sha256');
hash.update(code_verifier);
let code_challenge = hash.digest('base64');
// 3. ارسال درخواست به سرور
let params = {
client_id: "your_client_id",
redirect_uri: "http://localhost:8080/callback",
response_type: "code",
scope: "openid profile email",
code_challenge: code_challenge,
code_challenge_method: "S256"
};
let url = "https://your_identity_server/authorize?" + querystring.stringify(params);
// درخواست کاربر برای ورود
window.location = url;
مرحله دوم: دریافت authorization code
این مرحله بر اساس تنظیمات کلاینت شما در سرور Identity Server و برنامه شما متفاوت خواهد بود. ولی در نهایت، سرور یک "authorization code" را به URL بازگشتی (redirect URI) ارسال میکند.
// دریافت "authorization code" از URL
let urlParams = new URLSearchParams(window.location.search);
let authorization_code = urlParams.get("code");
مرحله سوم: تبدیل "authorization code" به "access token"
کلاینت باید "authorization code" را به همراه "code_verifier" اصلی به سرور ارسال کند تا "access token" را دریافت کند.
let params = {
client_id: "your_client_id",
redirect_uri: "http://localhost:8080/callback",
grant_type: "authorization_code",
code: authorization_code,
code_verifier: code_verifier
};
axios.post("https://your_identity_server/token", querystring.stringify(params))
.then(response => {
// دریافت "access token" از پاسخ سرور
let access_token = response.data.access_token;
// اکنون میتوانید از "access token" برای احراز هویت در سرویسهای بکاند استفاده کنید
})
.catch(error => {
// مدیریت خطا
});
توجه داشته باشید که این کدها تنها برای توضیح هدف کلی برنامهنویسی این فرآیند هستند و احتمالاً برای استفاده عملی نیاز به تغییراتی دارند. همچنین ممکن است نیاز به مدیریت خطاها و امنیت اضافی در برخی مراحل باشد.
با استفاده از IdentityServer4، شما میتوانید تنظیمات سرور خود را برای پشتیبانی از جریان کد اجازه با PKCE انجام دهید.
در زیر نحوه تعریف یک کلاینت در IdentityServer4 برای جریان کد اجازه با PKCE را میبینید:
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "your_client_id",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
AllowPlainTextPkce = false,
RedirectUris = { "http://localhost:8080/callback" },
PostLogoutRedirectUris = { "http://localhost:8080/" },
AllowedCorsOrigins = { "http://localhost:8080" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
},
ClientSecrets =
{
new Secret("your_secret".Sha256())
},
AccessTokenLifetime = 3600, // توکن برای 1 ساعت معتبر است
AllowOfflineAccess = true, // این امکان را فراهم میکند که توکن refresh دریافت کنید
}
};
}
این کد یک کلاینت با جریان grant type کد اجازه را تعریف میکند. ما مشخص کردیم که این کلاینت PKCE را نیاز دارد (RequirePkce = true) و ما نمیخواهیم که PKCE در متن ساده قابل قبول باشد (AllowPlainTextPkce = false).
همچنین توجه کنید که ما AllowOfflineAccess = true را تنظیم کردهایم، که به کلاینت اجازه میدهد تا یک توکن refresh دریافت کند. این باعث میشود تا کلاینت بتواند یک session کاربر را حفظ کند حتی وقتی که توکن access اولیه منقضی شده است.
اگر بخواهید تا کلاینت بتواند یکی از API های شما را فراخوانی کند، باید آن scope را نیز به AllowedScopes اضافه کنید.
توجه داشته باشید که شما باید your_client_id و your_secret را به مقادیری جایگزین کنید که برای برنامهی شما مناسب است. همچنین، RedirectUris, PostLogoutRedirectUris, و AllowedCorsOrigins باید به URL های معتبر برنامهی شما تنظیم شوند.
- 1402/02/30
خیلی از شما متشکرم که جواب من رو دادید.
من اینهمه در اینترنت گشتم ولی جواب درستی پیدا نکردم.
و بسیار ممنونم که برای این مسئله مثال هم قرار دادید.
موفق و سر زنده و سلامت باشید.
پاسخی برای این باگ ارسال کنید
لطفا کدها را درون قطعه کد ارسال نمایید
برای ارسال پاسخ باید وارد حساب کاربری خود شوید
ورود به حساب کاربری